/*!
* @file Referenced.h
* @brief 引用对象基类
* @date 2024/9/25
*/
#pragma once

#include <atomic>

namespace data
{
class Referenced
{
public:
    Referenced() = default;
    virtual ~Referenced() = default;

    /*!
    * @brief 获得对象被引用的数目
    * @return 引用计数个数
    */
    virtual int ReferenceCount() const = 0;

    /*!
    * @brief 增加引用计数
    */
    virtual void Ref() const = 0;

    /*!
    * @brief 减少引用计数，当引用计数的数目为零时，引用对象将被自动删除。
    */
    virtual void Unref() const = 0;

    /*!
    * @brief 减少对象的引用计数，但不执行删除操作
     *@remark 调用者需要知道谁负责该引用对象的删除，否则会造成内存泄露。
    */
    virtual void UnrefNoDelete() const = 0;
};

template<class T>
class RefPtr
{
public:
    using element_type = T;

    /*!
    * @brief 默认构造函数
    */
    RefPtr() noexcept : _ptr(nullptr) {}

    /*!
    * @brief 输入为裸指针的构造函数
    * @param[in] ptr 具有引用技术对象的裸指针
    */
    RefPtr(T* ptr) noexcept : _ptr(ptr) { if (_ptr) _ptr->Ref(); }

    /*!
    * @brief 拷贝构造函数
    * @param[in] rp 引用对象引用
    */
    RefPtr(const RefPtr& rp) noexcept : _ptr(rp._ptr) { if (_ptr) _ptr->Ref(); }

    /*!
    * @brief 拷贝构造函数
    */
    template<class R>
    RefPtr(const RefPtr<R>& rp) noexcept : _ptr(rp._ptr) { if (_ptr) _ptr->Ref(); }

    /*!
    * @brief 右值拷贝构造函数
    */
    template<class R>
    RefPtr(RefPtr<R>&& rp) noexcept : _ptr(rp._ptr) { rp._ptr = nullptr; }

    /*!
    * @brief 析构函数
    */
    ~RefPtr() { if (_ptr) _ptr->Unref();  _ptr = 0; }

    /*!
    * @brief 重载赋值符号
    */
    inline RefPtr& operator = (T* ptr)
    {
        if (_ptr == ptr) return *this;
        T* tmp_ptr = _ptr;
        _ptr = ptr;
        if (_ptr) _ptr->Ref();
        if (tmp_ptr) tmp_ptr->Unref();
        return *this;
    }

    /*!
    * @brief 重载赋值符号
    */
    RefPtr& operator = (const RefPtr& rp)
    {
        if (_ptr == rp._ptr) return *this;
        T* tmp_ptr = _ptr;
        _ptr = rp._ptr;
        if (_ptr) _ptr->Ref();
        if (tmp_ptr) tmp_ptr->Unref();
        return *this;
    }

    /*!
    * @brief 重载赋值符号
    */
    template<class R>
    RefPtr& operator = (const RefPtr<R>& rp)
    {
        if (_ptr == rp._ptr) return *this;
        T* tmp_ptr = _ptr;
        _ptr = rp._ptr;
        if (_ptr) _ptr->Ref();
        if (tmp_ptr) tmp_ptr->Unref();
        return *this;
    }

    /*!
    * @brief 重载赋值符号
    */
    template<class R>
    RefPtr& operator = (RefPtr<R>&& rp)
    {
        if (_ptr == rp._ptr) return *this;
        if (_ptr) _ptr->Unref();
        _ptr = rp._ptr;
        rp._ptr = nullptr;
        return *this;
    }

    /*!
    * @brief 重载相等比较符号
    */
    bool operator == (const RefPtr& rp) const { return (_ptr == rp._ptr); }
    bool operator == (const T* ptr) const { return (_ptr == ptr); }
    friend bool operator == (const T* ptr, const RefPtr& rp) { return (ptr == rp._ptr); }

    /*!
    * @brief 重载不等比较符号
    */
    bool operator != (const RefPtr& rp) const { return (_ptr != rp._ptr); }
    bool operator != (const T* ptr) const { return (_ptr != ptr); }
    friend bool operator != (const T* ptr, const RefPtr& rp) { return (ptr != rp._ptr); }

    /*!
    * @brief 重载小于比较符号
    */
    bool operator < (const RefPtr& rp) const { return (_ptr < rp._ptr); }

    /*!
    * @brief 重载取内容符号
    */
    T& operator*() const { return *_ptr; }

    /*!
    * @brief 重载访问符号
    */
    T* operator->() const { return _ptr; }

    /*!
    * @brief 获得裸指针
    */
    T* get() const { return _ptr; }

    /*!
    * @brief 判断指针是否有效
    */
    bool valid() const { return _ptr != 0; }

    /*!
    * @brief 重载取反符号
    */
    bool operator!() const { return _ptr == 0; } // not required

    /*!
    * @brief 重载bool变换
    */
    operator bool() const { return valid(); }

    /*!
    * @brief 释放对象引用
    */
    T* release() { T* tmp = _ptr; if (_ptr) _ptr->UnrefNoDelete(); _ptr = 0; return tmp; }

    /*!
    * @brief 隐式转换
    */
    operator T* () const { return _ptr; }

private:
    template<class R>
    friend class RefPtr;
    T* _ptr;
};

/*!
* @brief 简单引用对象模板
*/
template<class Referenced>
class ReferencedT : public Referenced
{
public:
    ReferencedT() : _referececount(0) {};

    virtual int ReferenceCount() const override { return _referececount; }
    virtual void Ref() const override { _referececount++; }
    virtual void Unref() const override { _referececount--; if (_referececount == 0) delete this; }
    virtual void UnrefNoDelete() const override { _referececount--; }

private:
    mutable std::atomic<int> _referececount;
};

}

template<class T, class Y> inline
data::RefPtr<T> static_pointer_cast(const data::RefPtr<Y>& rp) { return static_cast<T*>(rp.get()); }

template<class T, class Y> inline
data::RefPtr<T> dynamic_pointer_cast(const data::RefPtr<Y>& rp) { return dynamic_cast<T*>(rp.get()); }

template<class T, class Y> inline
data::RefPtr<T> const_pointer_cast(const data::RefPtr<Y>& rp) { return const_cast<T*>(rp.get()); }
